//
//  JKFilePathOperationCategory.swift
//  JKSwiftFileOperation
//
//  by 王冲 on 2018/4/17.
//  Copyright © 2018年 希艾欧科技有限公司. All rights reserved.
//
/*
   - 1、Home目录(应用程序包)
     - 整个应用程序各文档所在的目录,包含了所有的资源文件和可执行文件
   - 2、Documents
     - 保存应用运行时生成的需要持久化的数据，iTunes同步设备时会备份该目录
     - 需要保存由"应用程序本身"产生的文件或者数据，例如: 游戏进度，涂鸦软件的绘图
     - 目录中的文件会被自动保存在 iCloud
     - 注意: 不要保存从网络上下载的文件，否则会无法上架!
   3、tmp
     - 保存应用运行时所需要的临时数据或文件，"后续不需要使用"，使用完毕后再将相应的文件从该目录删除。
     - 应用没有运行，系统也可能会清除该目录下的文件
     - iTunes不会同步备份该目录
     - 重新启动手机, tmp 目录会被清空
     - 系统磁盘空间不足时，系统也会自动清理
   4、Library/Cache：保存应用运行时生成的需要持久化的数据，iTunes同步设备时不备份该目录。一般存放体积大、不需要备份的非重要数据
     - 保存临时文件,"后续需要使用"，例如: 缓存的图片，离线数据（地图数据）
     - 系统不会清理 cache 目录中的文件
     - 就要求程序开发时, "必须提供 cache 目录的清理解决方案"
   5、Library/Preference：保存应用的所有偏好设置，IOS的Settings应用会在该目录中查找应用的设置信息。iTunes
     - 用户偏好，使用 NSUserDefault 直接读写！
     - 如果想要数据及时写入硬盘，还需要调用一个同步方法 synchronize()
     UserDefaults是一种存轻量级的数据
     let userDefault = UserDefaults.standard
     userDefault.set("王冲", forKey: "name")
     userDefault.synchronize()
     useDefault.removeObject(forKey: "name")
*/

import UIKit

// 文件名字的枚举
enum FileOperatioNameEnum: String
{
    // 前面是枚举值 后面是原始值
    case Documents = "Documents/"
    case Library = "Library/"
    case LibraryCaches = "Library/Caches/"
    case temp = "tmp/"
    
    // 如果在枚举中利用static修饰一个方法 , 相当于类中的class修饰方法
    // 如果调用枚举值的rawValue, 那么意味着拿到枚举对应的原始值
    static func enumValue(value: Int) ->String
    {
        switch value {
        case 0:
            // 根目录下
            return ""
        case 1:
            return Documents.rawValue
        case 2:
            return Library.rawValue
        case 3:
            return LibraryCaches.rawValue
        case 4:
            return temp.rawValue
        default:
            return ""
        }
    }
}

class JKFilePathOperationCategory: NSObject {
    
    // MARK: 0.创建一个文件管理器
    let fileManager: FileManager = FileManager.default
    
    // MARK: 1.获取各个主目录
    // MARK: 获取程序的Home目录
    class func jKHomeDirectory() -> String{
        
        let homePath = NSHomeDirectory()
        return homePath
    }
    // MARK: 返回Documnets的完整路径名
    /**返回Documnets的完整路径名*/
    class func jKDocuments() -> String{
       
        //获取程序的documentPaths目录
        //方法1
        /*
          let documentPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
          let documnetPath = documentPaths[0]
          return documnetPath
        */
        //方法2
        return NSHomeDirectory()+"/Documents"
    }
    
    // MARK: 返回Caches的完整路径名
    /**返回Cache的完整路径名*/
    class func jKCache() -> String{
        
        //Cache目录－方法1
        /*
          let cachePaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
          //let cachePath = cachePaths.last
          let cachePath = cachePaths[0]
          return cachePath
         */
        
        //Cache目录－方法2
        return NSHomeDirectory()+"/Library/Caches"
    }
    
    // MARK: 返回Library的完整路径名
    /**返回Library的完整路径名*/
    class func jKLibrary() -> String{
        /*
          这个目录下有两个子目录：Caches 和 Preferences
          Library/Preferences目录，包含应用程序的偏好设置文件。不应该直接创建偏好设置文件，而是应该使用NSUserDefaults类来取得和设置应用程序的偏好。
          Library/Caches目录，主要存放缓存文件，iTunes不会备份此目录，此目录下文件不会再应用退出时删除
        */
        //Library目录－方法1
        /*
            let libraryPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.libraryDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
            let libraryPath = libraryPaths[0]
            return libraryPath
        */
        //Library目录－方法2
        return NSHomeDirectory()+"/Library"
    }
    
    // MARK: 返回Tmp的完整路径名
    /**返回Tmp的完整路径名*/
    class func jKTmp() -> String{
        // 用于存放临时文件，保存应用程序再次启动过程中不需要的信息，重启后清空
        //方法1
        //let tempPath = NSTemporaryDirectory()
        //方法2
        return NSHomeDirectory()+"/tmp"
    }
    
    // MARK: 自定义文件夹名字
    /** 1.自定义文件夹名字*/
    class func jKCustomPath(value:Int,customString: NSString) -> NSString
    {
        // MARK: 枚举的使用
        let enumValueStr: NSString = FileOperatioNameEnum.enumValue(value: value) as NSString
        let customPath: NSString = "\(enumValueStr)" + "\(customString)" as NSString
        return customPath
    }
    
    // MARK: 2.根据传件来的路径创建文件夹 创建文件目录(蓝色的，文件夹和文件是不一样的)
    // folderName:文件夹的名字
    /**2.根据传件来的路径创建文件夹 创建文件目录(蓝色的，文件夹和文件是不一样的)*/
    func jKCreateFolder(folderName: NSString) -> NSString {
        
        // NSHomeDirectory()：应用程序目录
        let filePath = "\(folderName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 不存在的路径才会创建
        if (!exist) {
        
            //withIntermediateDirectories为ture表示路径中间如果有不存在的文件夹都会创建
            try! fileManager.createDirectory(atPath: filePath,withIntermediateDirectories: true, attributes: nil)
        }
        return filePath as NSString
    }
    
    // MARK: 3.删除文件夹的路径
    /** 删除文件夹的路径*/
    func jKRemovefolder(folderName: NSString){
        
        let filePath = "\(folderName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 查看文件夹是否存在，如果存在就直接读取，不存在就直接反空
        if (exist) {
            
            try! fileManager.removeItem(atPath: filePath)
            
        }else{
            
            // 不存在就不做什么操作了
        }
    }
    
    // MARK: 4.删除文件的路径
    /** 删除文件的路径*/
    func jKRemovefile(folderName: NSString){
        
        let filePath = "\(folderName)"
        //移除文件
        try! fileManager.removeItem(atPath: filePath)
        
    }
    
    // MARK: 5.读取某个文件
    /** 读取某个文件*/
    func jKReadfile(folderName: NSString){
        
        let filePath = "\(folderName)"
        //移除文件
        let data = fileManager.contents(atPath: filePath)
        let readString2 = String(data: data!, encoding: String.Encoding.utf8)
        print("文件内容: \(String(describing: readString2))")
    }
    
    // MARK: 6.对指定路径执行浅搜索，返回指定目录路径下的文件、子目录及符号链接的列表(只寻找一层)
    /** 对指定路径执行浅搜索，返回指定目录路径下的文件、子目录及符号链接的列表(只寻找一层)*/
    func jKShallowSearchAllFiles(folderName: NSString) -> NSArray {
        
        let filePath = "\(folderName)"
        let contentsOfPathArray = try! fileManager.contentsOfDirectory(atPath: filePath)
        return contentsOfPathArray as NSArray
        
    }
    
    // MARK: 7.1、深度遍历，会递归遍历子文件夹（包括符号链接，所以要求性能的话用enumeratorAtPath）
    /**深度遍历，会递归遍历子文件夹（包括符号链接，所以要求性能的话用enumeratorAtPath）*/
    func jKGetAllFileNames(folderName: NSString) -> NSArray{
        
        let filePath = "\(folderName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 查看文件夹是否存在，如果存在就直接读取，不存在就直接反空
        if (exist) {
            let subPaths = fileManager.subpaths(atPath: folderName as String)
            return subPaths! as NSArray
        }else{
            return []
        }
    }
    // MARK: 7.2、深度遍历，会递归遍历子文件夹（但不会递归符号链接）
    /** 对指定路径深度遍历，会递归遍历子文件夹（但不会递归符号链接））*/
    func jKDeepSearchAllFiles(folderName: NSString) -> NSArray
    {
        let filePath = "\(folderName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 查看文件夹是否存在，如果存在就直接读取，不存在就直接反空
        if (exist) {
            let contentsOfPathArray = fileManager.enumerator(atPath: filePath)
            return contentsOfPathArray!.allObjects as NSArray
        }else{
            return []
        }
    }
    
    // MARK: 8、判断文件或文件夹是否存在
    /** 判断文件或文件夹是否存在*/
    func jkJudgeFileOrFolderExists(folderName: NSString) -> Bool
    {
        let filePath = "\(folderName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 查看文件夹是否存在，如果存在就直接读取，不存在就直接反空
        if (exist) {
            return true
        }else{
            return false
        }
    }
    
    // MARK: 9.根据传件来的路径创建文件
    // fileName:文件的名字（不是文件夹）
    // baseFilePath: 文件的基础路径
    // content: 存进文件的内容
    /** 根据传件来的路径创建文件*/
    func jKCreateFile(fileName: NSString,baseFilePath: NSString) -> (filePath: NSString,createStatus: Bool) {
        
        // NSHomeDirectory()：应用程序目录
        let filePath = "\(baseFilePath)" + "/\(fileName)"
        let exist = fileManager.fileExists(atPath: filePath)
        // 不存在的文件路径才会创建
        if (!exist) {
            
            //withIntermediateDirectories为ture表示路径中间如果有不存在的文件夹都会创建
           let createSuccess = fileManager.createFile(atPath: filePath,contents:nil,attributes:nil)
           return (filePath as NSString,createSuccess as Bool)
            
        }
        return (filePath as NSString,true)
    }
    
    // MARK: 10.把文字，图片，数组，字典写入文件
    /** 文字，图片，数组，字典写入文件 */
    class func jKWriteToFile(writeType:Int,content:Any,writePath:String)
    {
        // 1、文字，2、图片，3、数组，4、字典写入文件
        switch writeType {
        case 1:
            
            let info = "\(content)"
            try! info.write(toFile: writePath, atomically: true, encoding: String.Encoding.utf8)
            
            break
        case 2:
            
            let data = content as! Data
            try? data.write(to: URL(fileURLWithPath: writePath))
            
            break
        case 3:
            
            let array = content as! NSArray
            array.write(toFile: writePath, atomically: true)
            
            break
        case 4:
            
            let dictionary = content as! NSDictionary
            dictionary.write(toFile: writePath, atomically: true)
            
            break
        default: break
            
        }
       
    }
    
    // MARK: 11.复制文件
    /** 复制文件 fromeFile: 被复制的文件路径  toFile: 复制后的文件路径*/
    class func jKCopyFile(fromeFile: NSString,toFile: NSString){
    
        let fileManager1 = FileManager.default
        let fromUrl = "\(fromeFile)"
        let toUrl = "\(toFile)"
        try! fileManager1.copyItem(atPath: fromUrl as String, toPath: toUrl as String)
        
    }
    
    // MARK: 11.移动文件
    /** 移动文件 fromeFile: 被移动的文件路径  toFile: 移动后的文件路径*/
    class func jKMoveFile(fromeFile: NSString,toFile: NSString){
        
        let fileManagerMove = FileManager.default
        let fromUrl = "\(fromeFile)"
        let toUrl = "\(toFile)"
        try! fileManagerMove.moveItem(atPath: fromUrl as String, toPath: toUrl as String)
        
    }
    
    // MARK: 12.读出文本文件内容
    /** 读出文本文件内容 */
    class func jKReadTextToFile(readPath:String) -> String
    {
        let path = "\(readPath)"
        let readHandler =  FileHandle(forReadingAtPath: path)
        let data = (readHandler?.readDataToEndOfFile())!
        let readString = String(data: data, encoding: String.Encoding.utf8)
        //print("文件内容: \(String(describing: readString))")
        return readString!
   
    }
    
    // MARK: 13.读出图片
    /** 读出图片 imageStatus: 判断图片存在的状态 */
    class func jKReadImageFile(readPath:String) -> (imege:Any,imageStatus: Bool)
    {
        let path = "\(readPath)"
        let fileManagerReadImage = FileManager.default
        let exist = fileManagerReadImage.fileExists(atPath: path)
        // 不存在直接返回false
        if (!exist) {
            
            return (UIImage(),false)
            
        }else{
            
            let readHandler =  FileHandle(forReadingAtPath: path)
            let data = (readHandler?.readDataToEndOfFile())!
            let image = UIImage(data: data)
            return (image!,true)
        }
    }
    
    //MARK: 14、获取文件属性（创建时间，修改时间，文件大小，文件类型等信息）
    class func jKGetFileAttributes(filePath:String) -> [FileAttributeKey : Any]{
        
        let managerGetFile = FileManager.default
        let path = "\(filePath)"
        let attributes = try? managerGetFile.attributesOfItem(atPath: path) //结果为Dictionary类型
        //print("attributes: \(attributes!)")
        /*
         print("创建时间：\(attributes[FileAttributeKey.creationDate]!)")
         print("修改时间：\(attributes[FileAttributeKey.modificationDate]!)")
         print("文件大小：\(attributes[FileAttributeKey.size]!)")
         */
        return attributes!
       
    }
    
    //MARK: 15、计算文件夹或者文件的大小
    /** 计算文件夹或者文件的大小 */
    class func getSize(folderPath: String)-> String
    {
        if folderPath.count == 0 {
            return "0MB" as String
        }
        let manager = FileManager.default
        if !manager.fileExists(atPath: folderPath){
            return "0MB" as String
        }
        var fileSize:Float = 0.0
        do {
              let files = try manager.contentsOfDirectory(atPath: folderPath)
            
              for file in files {
                
                let path = folderPath + "/\(file)"
                fileSize = fileSize + fileSizeAtPath(filePath: path)
                
              }
            }catch{
                
                fileSize = fileSize + fileSizeAtPath(filePath: folderPath)
        }
        
        print("大小==\(fileSize)")
        
        var resultSize = ""
        
        if fileSize >= 1024.0*1024.0{
            
            resultSize = NSString(format: "%.2fMB", fileSize/(1024.0 * 1024.0)) as String

        }else if fileSize >= 1024.0{
            
            resultSize = NSString(format: "%.fkb", fileSize/(1024.0 )) as String
            
        }else{
            
            resultSize = NSString(format: "%llub", fileSize) as String
        }

        return resultSize
    }
    
    //MARK: 16、计算单个文件或文件夹的大小
    /**  计算单个文件或文件夹的大小 */
    class func fileSizeAtPath(filePath:String) -> Float {
        
        let manager = FileManager.default
        var fileSize:Float = 0.0
        if manager.fileExists(atPath: filePath) {
            do {
                let attributes = try manager.attributesOfItem(atPath: filePath)
                
                 if attributes.count != 0 {
                    
                    fileSize = attributes[FileAttributeKey.size]! as! Float
                  }
               }catch{
            
               }
          }
        
         return fileSize;
    }
    
}
